iT邦幫忙

2024 iThome 鐵人賽

DAY 5
0

Remix Action 與 Loader 一樣是伺服器端運行的程式碼,一樣可以取得 { request, params }。不同的地方只有名字跟 Method 是 POST、PUT、DELETE。Remix V1 是可以自訂 Method 的(就是定義除了 POST、PUT、DELETE 之外的方法),V2 就拿掉了。

本篇會提到

  1. action 程式碼
  2. Form 發送 POST、PUT、DELETE
  3. Submit 與 Fetcher.submit 發送 POST、PUT、DELETE

ref: Remix Action

程式碼範例

小提醒:在寫 type 的時候要記得 return 的東西要一致,不然前端的 actionData 會有很多版本很難搞。

// /app/route/user.tsx
// 後端程式碼 1. 確認使用者 session 2. 返回
export const action = async({ request, params }) => {
    const session = await getSession(request)
    
    if (!session) {
        // 這個 flash 可以在下個 route 讀取 session 並 commit 後自動消失,記得讀取後也要 commit Session 不然 flash 不會消失
        session.flash('errorMessage', ['請先登入再執行操作', 'Additional Info'])
        return redirect('/signin', {
            headers: {
                Set-Cookie: await commit Session(request)
            }
        })
    }
    
    if (request.method === 'PUT') {
        try {
            const result = await db.updateUserData(session)
            return json({ data: result, msg: 'Success updated user data', error: null })
        } catch (error) {
            console.error('Error in /user action', error)
            throw new Response('Internal error', 500)
        }
    } else {
        throw new Response('Method not allowed', 405)
    }
 }
 

// 前端程式碼
export default function User() {
    // 我省略 loader function,請見上篇
    const { user } = useLoaderData<typeof loader>()
    // 使用方法與 laoder 一樣,不過無法直接解構,因為一進來時 actionData 會是 undefined
    const actionData = useLoaderData<typeof action>()
    
    // 如果你是使用 Remix 的 Form,因為頁面不會重新載入,因此要使用 useEffect 聆聽 actionData 的變動
    useEffect(() => {
        if (actionData) alert(actionData.msg)
    }, [actionData])

    return (
        <></>
    )
}

前端提交觸發 action 的方式

Form

Form 是 Remix 的一個方便的 Component,如果是寫在同一個 route 下(也就是同個文件上面就是 action),可以在 Form 的地方省略指定 action 的位置,Remix 會自己找,不過如果你是在 _index 的 route 提交的,因為這個文件本身沒有建立 route,所以提交的位置是當個 /route?index。

ref: Index Query ParamForm

export default function Frontend() {
    const { user } = useLoaderData<typeof loader>();
  
    return (
    <div>
        <h3>{user.name}</h3>
        <Form method="post" action={'/user'}>
            <input type="text" name="name" />
            <button type="submit">Edit Name</button>
        </Form>
    </div>
    );
}

Submit

Submit 是來自 useSubmit() hook,是當你在提交 input 資料前,需要做些處理時會用到的。

import { useSubmit } from '@remix-run/react'
{...}

export default function Whatever() {
    const submit = useSubmit()

    {...}
    <Form
        onSubmit={e => {
            const form = e.currentTarget
            // 處理 form

            submit(form, {
                method: 'PUT',
                , encType: 'application/json', // submit 預設是使用 FormData,如果要以 JSON 傳送要設定這個
                navigate: false, // navigate 可以決定提交表單之後要不要跳轉
                ...otherOptions
            })
        }}
    {...}
}

Fetcher

Fetcher 的話適用於你要提交表單但不想跳轉,來自 useFetcher() hook,這個是我後來最常用到的 hook,他的 fetcher.submit() 就是跟上面的 submit 運作方式一樣,不過你可以取得 submit 後 route 返回的資料!這個對 Optimistic UI(使用者點了就先顯示,如果 DB 錯誤再顯示給使用者)非常有用!

不過不確定 submit 現在是不是也可以取得 route 返回的資料(看看下面 ref Sma Selicoff 的影片),不過官方都是用 fetcher。

Fetcher 剛開始接觸可能會有點難理解,以下的 ref 可以多看看!Remix Single 我斷斷續續看了有 20 次哈哈哈

ref: Remix Optimistic UIRemix Single: Optimistic UI - RemixOptimistic UI in Remix - Sam Selikoff


上一篇
[D4] Remix Loader
下一篇
[D6] Tailwind CSS + shadcn/ui = 😃
系列文
30 天練成全端 Remix 大師6
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言